/**
 * 行的数据
 * 树状图中指定列在行中的所有数据
 */
class ExSerie {
    /**
     * 构造函数
     * @param {Object} [option] 可选参数
     * @param {String} option.name 列的名字
     * @param {Array.<Number>} option.data 列的数据
     * @param {'line' | 'bar'} option.type 列的类型
     * @param {...Object} [option.args] 其他参数
     */
    constructor({
                    name,
                    data,
                    type,
                    ...args
                } = {}) {
        this.name = name
        this.data = data
        this.type = type
        Object.assign(this, args)
    }
}

/**
 * Echarts 的配置对象
 */
class ExOptions {
    /**
     * 构造函数
     * @param {ExOptions} [option] 可选参数
     * @param {Object} title 标题
     * @param {String} title.text 标题的文字
     * @param {Object} [tooltip] 鼠标悬浮的提示
     * @param {Object} legend 说明信息
     * @param {Array.<String>} legend.data 说明信息 => 纵轴分类
     * @param {Object} xAxis 横轴信息
     * @param {String} xAxis.data 横轴信息 => 横轴下面的文字信息
     * @param {Object} yAxis 纵轴信息
     * @param {'value'} yAxis.type 纵轴信息 => 纵轴的类型
     * @param {ExSerie} series 数据
     * @param {...Object} [option.args] 其他参数
     */
    constructor({
                    title,
                    tooltip = {},
                    legend,
                    xAxis,
                    yAxis = {
                        type: 'value',
                    },
                    series,
                    ...args
                } = {}) {
        this.title = title
        this.tooltip = tooltip
        this.legend = legend
        this.xAxis = xAxis
        this.yAxis = yAxis
        this.series = series
        Object.assign(this, args)
    }
}

function zeroAllField(obj) {
    return Object.keys(obj).reduce((res, k) => {
        res[k] = 0
        return res
    }, {})
}

function fillVacancy(data, sorted, sortedMax, dateType, classMap) {
    const _data = data.slice()
    const sortedSet = new Set(_data.map(obj => obj[sorted]))
    const first = _data[0] || classMap.get(dateType)
    for (let i = 1; i <= sortedMax; i++) {
        if (!sortedSet.has(i)) {
            const item = zeroAllField(first)
            item[sorted] = i
            _data.push(item)
        }
    }
    return _data
}

/**
 * 行转列
 * @param data 数据列表
 * @param cols 需要的列
 * @param sorted 排序的字段，只能是 月，星期，或者日
 * @param sortedMax 排序字段的最大值
 * @param dateType 当前的日期类型
 * @returns {Object} 排序好的字段 => 数据数组
 */
function row2col({
                     data, cols, sorted, sortedMax, dateType, classMap,
                 }) {
    return _.chain(fillVacancy(data, sorted, sortedMax, dateType, classMap))
        .flatMap(row => cols.map(col => [col, row]))
        .groupBy(([k]) => k)
        .mapValues(arr =>
            _.chain(arr)
                .sortBy(([, v]) => v[sorted])
                .map(([k, v]) => v[k])
                .value(),
        )
        .value()
}

function callDateColsMap(dateNow) {
    const now = rx.dateEnhance(dateNow)
    return new Map()
        .set(1, rx.range(1, now.monthOfYear() + 1).map(i => i + ' 月'))
        .set(2, rx.range(1, now.weekOfYear() + 1).map(i => i + ' 周'))
        .set(3, rx.range(1, now.dayOfMonth() + 1)
            .map(i => i + ' 日'))
}

function callDateMax(dateNow, dateType) {
    const now = rx.dateEnhance(dateNow)
    return new Map()
        .set(1, now.monthOfYear() + 1)
        .set(2, now.weekOfYear() + 1)
        .set(3, now.dayOfMonth() + 1)
        .get(dateType)
}

const dateTypeMap = new Map()
    .set(1, 'month')
    .set(2, 'week')
    .set(3, 'day')